-
Notifications
You must be signed in to change notification settings - Fork 1.1k
U5: Enable MSI auto calibration and compute frequencies #4313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Thanks for the PR! From looking at the RM, it seems to me MSI PLL is only usable when LSE is exactly 32768hz, and therefore the MSI freq will always be exactly what's specified by MSIRANGE, so we can always use |
We have tested this in the lab with a 32000 Hz source, over wide temperature ranges, and have found that the "PLL" works over a wider range of temperatures. It is not described as a PLL in the documentation, but as "auto-calibration feature" , and I believe it is implemented by a couple of counters that are in a control loop with the calibration function. The calibration function has a wide offset range (+/- several % ) , and it is reasonable to assume that a similar range of input frequencies must work for the reference. |
"when a 32.768khz external oscillator is present" strongly implies other frequencies are not supported. Also, the section for the LSE also says it must be a 32768hz crystal. Other frequencies are only allowed in bypass mode. And "when a 32.768khz external oscillator is present" also implies it must be an oscillator, not bypass mode. STM32CubeMX only allows 32768hz if LSE is a crystal. It doesn't seem to complain if you enable MSI PLL and set LSE to another frequency, but it doesn't change the MSI frequency based on it like this PR does. Do you have a source from ST stating this is supported? I'm a bit hesitant of adding support for running out of spec if it increases complexity. |
@@ -131,7 +131,18 @@ pub(crate) unsafe fn init(config: Config) { | |||
PWR.vosr().modify(|w| w.set_vos(config.voltage_range)); | |||
while !PWR.vosr().read().vosrdy() {} | |||
|
|||
let msis = config.msis.map(|range| { | |||
let lse_calibration_freq = match config.ls.lse { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of automatically deciding to enable msipll, could you add it to the config so the user explicitly chooses to. It could be None
, Some(Msik)
or Some(Msis)
.
If ther'es no LSE or the freq is too off just panic, this way the user notices if they do something wrong instead of it silently doing no calibration.
/// Based on STM32U5 datasheet table for LSE = 32.768 kHz | ||
fn get_msi_calibration_fraction(range: Msirange) -> MsiFraction { | ||
match range { | ||
Msirange::RANGE_48MHZ => MsiFraction::new(1465, 1), // Range 0: 48.005 MHz |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for each "group" of 4 the numerator is the same and the denominator is 1, 2, 3, 4. Maybe this can help compactify the table?
Msirange::RANGE_48MHZ => MsiFraction::new(1465, 1), // Range 0: 48.005 MHz
Msirange::RANGE_24MHZ => MsiFraction::new(1465, 2), // Range 1: 24.003 MHz
Msirange::RANGE_16MHZ => MsiFraction::new(1465, 3), // Range 2: 16.002 MHz
Msirange::RANGE_12MHZ => MsiFraction::new(1465, 4), // Range 3: 12.001 MHz
Msirange::RANGE_4MHZ => MsiFraction::new(122, 1), // Range 4: 3.998 MHz
Msirange::RANGE_2MHZ => MsiFraction::new(122, 2), // Range 5: 1.999 MHz
Msirange::RANGE_1_33MHZ => MsiFraction::new(122, 3), // Range 6: 1.333 MHz
Msirange::RANGE_1MHZ => MsiFraction::new(122, 4), // Range 7: 0.999 MHz
Msirange::RANGE_3_072MHZ => MsiFraction::new(94, 1), // Range 8: 3.08 MHz
Msirange::RANGE_1_536MHZ => MsiFraction::new(94, 1), // Range 9: 1.54 MHz
Msirange::RANGE_1_024MHZ => MsiFraction::new(94, 3), // Range 10: 1.027 MHz
Msirange::RANGE_768KHZ => MsiFraction::new(94, 4), // Range 11: 0.77 MHz
Msirange::RANGE_400KHZ => MsiFraction::new(12, 1), // Range 12: 393 kHz
Msirange::RANGE_200KHZ => MsiFraction::new(12, 2), // Range 13: 196.6 kHz
Msirange::RANGE_133KHZ => MsiFraction::new(12, 3), // Range 14: 131 kHz
Msirange::RANGE_100KHZ => MsiFraction::new(12, 4), // Range 15: 98.3 kHz
if let Some(freq) = lse_calibration_freq { | ||
let msik_freq = calculate_calibrated_msi_frequency(range, freq); | ||
if config.msis == config.msik { | ||
// If MSIS and MSIK are the same range both will be auto calibrated to the same frequency |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
they don't need to be the exact same, it's enough if they're in the same RC (group of 4)
This adresses #4312